package de.mwa.jersey.todo.resources;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Iterator; 
import java.util.Date;
import java.util.Random;

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import de.mwa.jersey.todo.dao.TodoDao;
import de.mwa.jersey.todo.model.Todo;
import de.mwa.jersey.todo.model.HibernateTodo;
import de.mwa.jersey.todo.maintenance.LogMgmt;


// Will map the resource to the URL todos
@Path("/todos")
public class TodosResource {
	private static SessionFactory factory; 
	LogMgmt log = new LogMgmt();
	
	
	public TodosResource() {
		writeLog("TodosResource - Constructor - Start");
	      try{
	          factory = new Configuration().configure().buildSessionFactory();
	       }catch (Throwable ex) { 
	    	   writeLog("Failed to create sessionFactory object." + ex);
	          throw new ExceptionInInitializerError(ex); 
	       }
	      writeLog("TodosResource - Constructor - End");
	}
  // Allows to insert contextual objects into the class, 
  // e.g. ServletContext, Request, Response, UriInfo
  @Context
  UriInfo uriInfo;
  @Context
  Request request;


  // Return the list of todos to the user in the browser
  @GET
  @Produces(MediaType.TEXT_XML)
  public List<Todo> getTodosBrowser() {
    //List<Todo> todos = new ArrayList<Todo>();
    //todos.addAll(TodoDao.instance.getModel().values());
	List<Todo> todos = listHibernateTodos();
    return todos; 
  }
  
  // Return the list of todos for applications
  @GET
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  public List<Todo> getTodos() {
    //List<Todo> todos = new ArrayList<Todo>();
    //todos.addAll(TodoDao.instance.getModel().values());
    List<Todo> todos = listHibernateTodos();
    return todos; 
  }
  
  
  // retuns the number of todos
  // use http://localhost:8080/de.vogella.jersey.todo/rest/todos/count
  // to get the total number of records
  @GET
  @Path("count")
  @Produces(MediaType.TEXT_PLAIN)
  public String getCount() {
    int count = TodoDao.instance.getModel().size();
    writeLog("getCount() - " + count);
    return String.valueOf(count);
  }
  
  @POST
  @Produces(MediaType.TEXT_HTML)
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public void newTodo(@FormParam("id") String id,
      @FormParam("summary") String summary,
      @FormParam("description") String description,
      @Context HttpServletResponse servletResponse) throws IOException {
    Todo todo = new Todo(id,summary);
    if (description!=null){
      todo.setDescription(description);
    }
    TodoDao.instance.getModel().put(id, todo);
    
    createHibernateTodo(summary, description);
    
    
    servletResponse.sendRedirect("../create_todo.html");
  }
  
  
  // Defines that the next path parameter after todos is
  // treated as a parameter and passed to the TodoResources
  // Allows to type http://localhost:8080/de.vogella.jersey.todo/rest/todos/1
  // 1 will be treaded as parameter todo and passed to TodoResource
  @Path("{todo}")
  public TodoResource getTodo(@PathParam("todo") String id) {
    return new TodoResource(uriInfo, request, id);
  }
  
  @POST
  @Path("new")
  public void createNewTodo( ) {
	  Random rand = new Random(1000000);
	  createHibernateTodo("Summary: " + rand.nextInt(), "Description: " + rand.nextInt());
  }
  // Hibernate stuff - Tutorial http://www.tutorialspoint.com/hibernate/hibernate_examples.htm translated to Todo Example
  
  public void createHibernateTodo(String summary, String description) {
	  System.out.println("createHibernateTodo");
    Session session = factory.openSession();
    Transaction tx = null;
    Integer hibernateTodoID = null;
    try{
       tx = session.beginTransaction();
       HibernateTodo hibernateTodo = new HibernateTodo(summary, description);
       hibernateTodoID = (Integer) session.save(hibernateTodo); 
       tx.commit();
    }catch (HibernateException e) {
       if (tx!=null) tx.rollback();
       e.printStackTrace(); 
    }finally {
       session.close(); 
	}	  
  }
  
  public List<Todo> listHibernateTodos(){
	  writeLog("  called listHibernateTodos()");
	  writeLog("  before factory.openSession()");
      Session session = factory.openSession();
      writeLog("  after factory.openSession()");
      Transaction tx = null;
      List<Todo> list = new ArrayList<Todo>();
      try{
    	  writeLog("  listHibernateTodos() - 1");

         tx = session.beginTransaction();
         List hibernateTodos = session.createQuery("FROM Todo").list(); 
         writeLog("  listHibernateTodos() - 2");

         for (Iterator iterator = 
                           hibernateTodos.iterator(); iterator.hasNext();){
            HibernateTodo hibernateTodo = (HibernateTodo) iterator.next();
            
            Todo todo = new Todo(""+hibernateTodo.getId(), hibernateTodo.getSummary());
            todo.setDescription(hibernateTodo.getDescription());
            
            list.add(todo);
         }
         writeLog("  listHibernateTodos() - 3");
         tx.commit();
         writeLog("  listHibernateTodos() - 4");
      }catch (HibernateException e) {
    	  writeLog("  listHibernateTodos() - HibernateException! : " + e.getMessage());
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      }finally {
         session.close(); 
      }
      
      return list;
   }
  
  /* Method to UPDATE salary for an employee */
  public void updateHibernateTodo(Integer HibernateTodoID, String description ){
     Session session = factory.openSession();
     Transaction tx = null;
     try{
        tx = session.beginTransaction();
        HibernateTodo hibernateTodo = 
                   (HibernateTodo)session.get(HibernateTodo.class, HibernateTodoID); 
        hibernateTodo.setDescription( description );
		 session.update(hibernateTodo); 
        tx.commit();
     }catch (HibernateException e) {
        if (tx!=null) tx.rollback();
        e.printStackTrace(); 
     }finally {
        session.close(); 
     }
  }
  
  /* Method to DELETE an employee from the records */
  public void deleteHibernateTodo(Integer hibernateTodoID){
     Session session = factory.openSession();
     Transaction tx = null;
     try{
        tx = session.beginTransaction();
        HibernateTodo hibernateTodo = 
                  (HibernateTodo)session.get(HibernateTodo.class, hibernateTodoID); 
        session.delete(hibernateTodo); 
        tx.commit();
     }catch (HibernateException e) {
        if (tx!=null) tx.rollback();
        e.printStackTrace(); 
     }finally {
        session.close(); 
     }
  }
  
  private void writeLog(String stringToWrite) {
	  try {
		log.writeLog("  - listHibernateTodos() - " + stringToWrite);
	} catch (IOException e1) {
		// TODO Auto-generated catch block
		e1.printStackTrace();
	}
  }
} 
